/* *****************************************************************
 * 
 * ESP8266实现了MQTT客户端
 * 
 * *****************************************************************/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define USE_DEBUG
#define DEBUG_SERIAL Serial

#ifdef USE_DEBUG
#define DEBUG_PRINT(...)                 \
	{                                         \
		DEBUG_SERIAL.print(__VA_ARGS__); \
	}
#define DEBUG_PRINTLN(...)                 \
	{                                           \
		DEBUG_SERIAL.println(__VA_ARGS__); \
	}
#else
#define DEBUG_PRINT(...) \
	{                         \
	}
#define DEBUG_PRINTLN(...) \
	{                           \
	}
#endif

// WiFi settings
const char *ssid = "GOODLUCKY";      // Replace with your WiFi name
const char *password = "xbgs721300";   // Replace with your WiFi password

// MQTT Broker settings
const char *mqtt_broker = "broker.emqx.io";  // EMQX broker endpoint
const char *mqtt_username = "emqx";  // MQTT username for authentication
const char *mqtt_password = "public";  // MQTT password for authentication
const int mqtt_port = 1883;  // MQTT port (TCP)

/*
发送消息格式：
@A,255,10\n 前进全速,10为持续时间
@B,128,5\n 后退半速
@L,128,10\n 半速向左
@R,128,20\n 半速向右
@C,0\n 停止
@M,1,0\n  开关灯,1为左灯 2为右灯, 第二个数字0为关, 1为开
@F,A1A2A3A4\n 红外发射数据

返回消息格式：
@Q,80\n 电池电量
@T,25,60\n 温湿度数据
@P,1\n 人体感应数据,时间戳由MQTT发送时间确定
@S,100\n 超声波检测距离数据
@W,100\n  轮子速度数据
*/

//订阅消息列表
const char *mqtt_topics[] = {
    "homegzcar/set/ahead",
    "homegzcar/set/back",
    "homegzcar/set/left",
    "homegzcar/set/right",
    "homegzcar/set/stop",
    "homegzcar/set/light",
    "homegzcar/set/infared",
    "homegzcar/get/battery",
    "homegzcar/get/temperature",
    "homegzcar/get/bodysense",
    "homegzcar/get/sonar",
    "homegzcar/get/wheel",
};

enum MQTT_TOPICS {
    MQTT_TOPIC_AHEAD = 0,
    MQTT_TOPIC_BACK,
    MQTT_TOPIC_LEFT,
    MQTT_TOPIC_RIGHT,
    MQTT_TOPIC_STOP,
    MQTT_TOPIC_LIGHT,
    MQTT_TOPIC_INFRARED,
    MQTT_TOPIC_BATTERY,
    MQTT_TOPIC_TEMPERATURE,
    MQTT_TOPIC_BODYSENSE, 
    MQTT_TOPIC_SONAR,
    MQTT_TOPIC_WHEEL,
    MQTT_TOPIC_COUNT,
};

WiFiClient espClient;
PubSubClient mqtt_client(espClient);

void connectToWiFi();
void connectToMQTTBroker();
void mqttCallback(char *topic, byte *payload, unsigned int length);

void setup() {
    Serial.begin(115200);
    connectToWiFi();
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTTBroker();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        DEBUG_PRINT(".");
    }
    DEBUG_PRINTLN("\nConnected to the WiFi network");
}

void connectToMQTTBroker() {
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        DEBUG_PRINT("Connecting to MQTT Broker as");
        DEBUG_PRINTLN(client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            DEBUG_PRINTLN("Connected to MQTT broker");
            for(int i=0; i<MQTT_TOPIC_COUNT; i++)
                mqtt_client.subscribe(mqtt_topics[i]);
            // 发布一条测试消息
            mqtt_client.publish(mqtt_topics[MQTT_TOPIC_LIGHT], "Hi EMQX I'm ESP8266 ^^");
        } else {
            DEBUG_PRINT("Failed to connect to MQTT broker, rc=");
            DEBUG_PRINT(mqtt_client.state());
            DEBUG_PRINTLN(" try again in 5 seconds");
            delay(5000);
        }
    }
}

void mqttCallback(char *topic, byte *payload, unsigned int length) {
    DEBUG_PRINT("Message received on topic: ");
    DEBUG_PRINTLN(topic);
    DEBUG_PRINT("Message:");

    // 将payload转换为字符串并添加结束符
    char messageBuffer[length + 1];
    memcpy(messageBuffer, payload, length);
    messageBuffer[length] = '\0';
    
    // 输出消息内容
    DEBUG_PRINT(messageBuffer);

    //发送给ESP8266
    Serial.print(messageBuffer);
           
    DEBUG_PRINTLN();
    DEBUG_PRINTLN("-----------------------");
}

void serialRecvEvent() {
    static String serialBuffer = "";
    while (Serial.available()) {
        char inChar = (char)Serial.read();
        if (inChar == '\n') {
            // 处理完整的命令
            DEBUG_PRINT("Received from Serial: ");
            DEBUG_PRINTLN(serialBuffer);
            // 这里可以根据需要处理serialBuffer中的命令
            if(serialBuffer.length() > 0) {
                if(serialBuffer[0] == '@'){
                    if(serialBuffer.length() > 1) {
                        char cmdType = serialBuffer[1];
                        int lastIndex = serialBuffer.indexOf('\n');
                        if(lastIndex == -1) {   //没有找到换行符
                            lastIndex = serialBuffer.length();
                        }
                        String cmdPayload = serialBuffer.substring(2, lastIndex);
                        switch(cmdType) {
                            case 'Q': // 电池电量
                                mqtt_client.publish(mqtt_topics[MQTT_TOPIC_BATTERY], cmdPayload.c_str());
                                break;
                            case 'T': // 温湿度
                                mqtt_client.publish(mqtt_topics[MQTT_TOPIC_TEMPERATURE], cmdPayload.c_str());
                                break;
                            case 'P': // 人体感应触发时间
                                mqtt_client.publish(mqtt_topics[MQTT_TOPIC_BODYSENSE], cmdPayload.c_str());
                                break;
                            case 'S': // 超声波距离
                                mqtt_client.publish(mqtt_topics[MQTT_TOPIC_SONAR], cmdPayload.c_str());
                                break;
                            case 'W': // 轮子速度
                                mqtt_client.publish(mqtt_topics[MQTT_TOPIC_WHEEL], cmdPayload.c_str());
                                break;
                            default:
                                DEBUG_PRINTLN("Unknown command type");
                                break;
                        }
                    }
                }
            }
            serialBuffer = ""; // 清空缓冲区
        } else {
            serialBuffer += inChar; // 添加字符到缓冲区
        }
    }
}

void loop() {
    if (!mqtt_client.connected()) {
        connectToMQTTBroker();
    }
    mqtt_client.loop();
    
    ///////////////////////////
	//循环检测串口
	serialRecvEvent();
}